package com.angel.common.helpers;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.collections15.CollectionUtils;
import org.apache.commons.collections15.Predicate;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

/** The <code>ReflectionHelper.class</code> helps you to get some reflection's objects in a easier way.
 *  All its methods are statics.
 *
 * @author William
 * @version
 */
public class ReflectionHelper {
	/** It is the logger for the class. */
	private static Logger logger = Logger.getLogger(ReflectionHelper.class);

	/** Define a Constant for null class array used when invoke a method. */
	public static final Class<?>[] NULL_CLASS_ARRAY = null;

	/** Define a Constant for null class array used when get a method from a object. */
	public static final Object[] NULL_OBJECT_ARRAY = null;

	/** Define a Constant for the get method prefix. It is used to complete a method name. */
	private static String GET_PREFIX_METHOD = "get";

	/** Define a Constant for the set method prefix. It is used to complete a method name. */
	private static String SET_PREFIX_METHOD = "set";

	/** Define a Constant for the set method prefix. It is used to complete a method name. */
	private static String GET_BOOLEAN_PREFIX_METHOD = "is";

	/** Define a Constant for the string class parameter type. It is used to invoke a method with parameters. */
	public static final Class<?>[] STRING_CLASS_PARAMETER_TYPE = new Class<?>[]{String.class};

	/** Define a Constant for the integer class parameter type. It is used to invoke a method with parameters. */
	public static final Class<?>[] INTEGER_CLASS_PARAMETER_TYPE = new Class<?>[]{Integer.class};

	/** Define a Constant for the boolean class parameter type. It is used to invoke a method with parameters. */
	public static final Class<?>[] BOOLEAN_CLASS_PARAMETER_TYPE = new Class<?>[]{Boolean.class};

	/** Define a Constant for the character class parameter type. It is used to invoke a method with parameters. */
	public static final Class<?>[] CHARACTER_CLASS_PARAMETER_TYPE = new Class<?>[]{Character.class};

	/** Define a Constant for the serializable class parameter type. It is used to invoke a method with parameters. */
	public static final Class<?>[] SERIALIZABLE_CLASS_PARAMETER_TYPE = new Class<?>[]{Serializable.class};

	/** Define a Constant for the short class parameter type. It is used to invoke a method with parameters. */
	public static final Class<?>[] SHORT_CLASS_PARAMETER_TYPE = new Class<?>[]{Short.class};

	/** Define a Constant for the char sequence class parameter type. It is used to invoke a method with parameters. */
	public static final Class<?>[] CHAR_SEQUENCE_CLASS_PARAMETER_TYPE = new Class<?>[]{CharSequence.class};

	/** Define a Constant for the class class parameter type. It is used to invoke a method with parameters. */
	public static final Class<?>[] CLASS_CLASS_PARAMETER_TYPE = new Class<?>[]{Class.class};

	private ReflectionHelper(){
		super();
	}

	/** Set current log level.
	 *
	 * @param logLevel
	 */
	public static void setLogLevel(Level logLevel){
		logger.setLevel(logLevel);
	}

	/** Return true, if the class name implements interfaces class name. Otherwise it returns false.
	 *
	 * @param className
	 * @param interfaceName
	 * @return
	 */
	public static boolean implementsInterfaceName(String className, String interfaceName){
		boolean isImplemented = false;
		Class<?> objectClass = getClassFrom(className);
		Class<?> interfaceClass = getClassFrom(interfaceName);
		isImplemented = implementsInterfaceName(objectClass, interfaceClass);
		return isImplemented;
	}

	/** Return true, if the objectClass implements interfaces class. Otherwise it returns false.
	 *
	 * @param objectClass
	 * @param interfaceClass
	 * @return
	 */
	public static boolean implementsInterfaceName(Class<?> objectClass, Class<?> interfaceClass){
		boolean isImplemented = false;
		if(!interfaceClass.isInterface()){
			return isImplemented;
		}
		Class<?>[] objectClassesImplemented = objectClass.getInterfaces();
		for(int i = 0; i < objectClassesImplemented.length; i++){
			if(objectClassesImplemented[i].getName().equals(interfaceClass.getName())){
				isImplemented = true;
			}
		}
		return isImplemented;
	}

	public static boolean inheritClassFrom(Class<?> subClass, Class<?> superClass){
		boolean isInherited = false;
		Class<?> superClassInherited = subClass.getSuperclass();
		while( !isInherited && (superClassInherited != null && !superClassInherited.equals(Object.class))){
			if(superClassInherited.equals(superClass)){
				isInherited = true;
			} else {
				superClassInherited = superClassInherited.getSuperclass();
			}
		}
		return isInherited;
	}

	public static boolean implementsListMethod(Class<?> objectClass, List<Method> methodImplemented){
		boolean implementsAllMethods = true;
		Method[] methodObjectClass = objectClass.getMethods();

		Method currentMethodImplemented = null;
		for(int i = 0; i < methodImplemented.size(); i++){
			currentMethodImplemented = methodImplemented.get(i);
			for(int j = 0; j < methodObjectClass.length; j++){
				if(!methodObjectClass[i].getName().equals(currentMethodImplemented.getName())){
					implementsAllMethods = false;
				}
			}
		}
		return implementsAllMethods;
	}

	/** Return true, if objectClass or some objectClass's superclass implements interfaceClass. Otherwise it returns false.
	 *
	 * @param objectClass
	 * @param interfaceClass
	 * @return
	 */
	public static boolean implementsInterfaceRecursive(Class<?> objectClass, Class<?> interfaceClass){
		boolean isImplemented = false;

		if(!interfaceClass.isInterface()){
			return isImplemented;
		}
		Class<?>[] interfacesImplemented = objectClass.getInterfaces();

		if( !isImplemented && !objectClass.equals(Object.class) ){
			for(int i = 0; i < interfacesImplemented.length; i++){
				if(interfacesImplemented[i].getName().equals(interfaceClass.getName())){
					isImplemented = true;
					return isImplemented;
				}
			}
			isImplemented = implementsInterfaceRecursive(objectClass.getSuperclass(), interfaceClass);
		}
		return isImplemented;
	}

	/** Return a List with all objectClass' subclasses except if objectClass' superClass is Object class, or objectClass is object class.
	 *
	 * @param objectClass
	 * @return
	 */
	public static List<Class<?>> getAllSubClasses(Class<?> objectClass){
		List<Class<?>> subClasses = new ArrayList<Class<?>>();
		Class<?> superClass = null;

		while((superClass = objectClass.getSuperclass()) != null && !superClass.equals(Object.class)){
			subClasses.add(superClass);
			objectClass = superClass;
		}
		return subClasses;
	}

	/** Return true, if the objectClass implements interfaces class name. Otherwise it returns false.
	 *
	 * @param objectClass
	 * @param interfaceName
	 * @return
	 */
	public static boolean implementsInterfaceName(Class<?> objectClass, String interfaceName){
		boolean isImplemented = false;
		Class<?> interfaceClass = getClassFrom(interfaceName);
		isImplemented = implementsInterfaceName(objectClass, interfaceClass);
		return isImplemented;
	}

	/** Return an object, witch is getted with the methodName from the clazz, applied to the object.
	 *  The clazz's method mustn't have parameters, because here it is null.
	 *
	 * @param clazz
	 * @param methodName
	 * @param object
	 * @return Object
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static Object getObjectFrom(Class<?> clazz, String methodName, Object object) {
		String className = clazz.getSimpleName();
		Method method;
		Object obj = null;
		try {
			method = clazz.getMethod(methodName, NULL_CLASS_ARRAY);
			obj = method.invoke(object, NULL_OBJECT_ARRAY);
		} catch (SecurityException e) {
			logger.error("There was an error in the securiry -> ", e);
		} catch (NoSuchMethodException e) {
			logger.error("Not found method " + methodName + " in the object class: " + className + ".", e);
		} catch (IllegalArgumentException e) {
			logger.error("Ilegal arguments were found in the method " + methodName + " in the object class: " + className + ".", e);
		} catch (IllegalAccessException e) {
			logger.error("An ilegal access to method " + methodName + " in the object class: " + className + ".", e);
		} catch (InvocationTargetException e) {
			logger.error("Ilegal invocation target to method " + methodName + " in the object class: " + className + ".", e);
		}
		return obj;
	}

	/** Return an object from the class "clazz".
	 * If the new instance cannot be returned, it returns null.
	 * @param clazz
	 * @return
	 */
	public static Object getAnInstanceFrom(Class<?> clazz){
		Object object = null;
		try{
			object = clazz.newInstance();
		} catch (InstantiationException e) {
			logger.error("There was an error in the Instatiation from class: " + clazz, e);
		} catch (IllegalAccessException e) {
			logger.error("There was an illegas access in the Instatiation from class: " + clazz, e);
		}
		return object;
	}

	/** Get an instance from clazzName's class. First get the class with class name, and then it creates a
	 *  new instance from that class, and return it.
	 *
	 * @since 1.0.1
	 * @param clazzName
	 * @return an instance of an object whitch class name is "ClazzName".
	 */
	public static Object getAnInstanceFrom(String clazzName){
		Class<?> clazz = getClassFrom(clazzName);
		return getAnInstanceFrom(clazz);
	}

	/** Return an object witch is getted in the follow way:
	 * 		The first String object in the "methodsNames" Array, is invoked to the object.
	 * 		When the first method was invoked to the object, it returns another new object.
	 * 		Then it is repeted till the the "methodsNames" Array is finished.
	 *
	 * @param object
	 * @param methodsNames
	 * @return
	 */
	public static Object getObjectReflectionRecursiveFrom(Object object, String[] methodsNames){
		Object result = null;
		int methodSize = methodsNames.length;
		Class<?> clazz = object.getClass();
		try {
			String aux = null;
			for(int i = 0; i < methodSize ; i++){
				clazz = object.getClass();
				aux = methodsNames[i];
				object = getObjectFrom(clazz, aux, object);
			}
			result = object;
		} catch (SecurityException e) {
			logger.error("There was an error in the securiry -> ", e);
		}
		return result;
	}

	/** Return a Class Object with the className by parameter.
	 *  If the class name doesn't exist, it returns null.
	 *
	 * @param className
	 * @return
	 */
	public static Class<?> getClassFrom(String className){
		Class<?> clazz = null;
		try {
			clazz = Class.forName(className);
		} catch (ClassNotFoundException e) {
			logger.error("Class " + className + " not found.", e);
		}
		return clazz;
	}

	/** Return a Method Object from the object with the "methodName" like name.
	 *  This method mustn't have parameter in its signature.
	 *
	 * @param object
	 * @param methodName
	 * @return
	 */
	public static Method getMethodWithoutParameters(Object object, String methodName){
		return getMethod(object, methodName, NULL_CLASS_ARRAY);
	}

	/** Return an array with all object's methods.
	 *
	 * @param object
	 * @return
	 */
	public static Method[] getMethods(Object object){
		Class<?> clazzObject = object.getClass();
		return clazzObject.getMethods();
	}

	/** Verify if the Object "object" contains a method with name "methodName".
	 *
	 * @param object
	 * @param methodName
	 * @return It returns true if the object contains a method with name "methodName". Otherwise it return false.
	 */
	public static boolean containsMethodName(Object object, String methodName){
		boolean contains = false;
		Method[] methods = getMethods(object);
		Method currentMethod = null;
		for(int i = 0; i < methods.length; i++){
			currentMethod = methods[i];
			if(currentMethod.getName().equalsIgnoreCase(methodName)){
				contains = true;
				i = methods.length;
			}
		}
		return contains;
	}

	/** Verify if a class contains get and set method for a class' property. If it contains these methods, it returns true. Otherwise it returns false.
	 *
	 * @param clazz
	 * @param fieldName
	 * @return
	 */
	public static boolean containsGetAndSetMethodForField(Class<?> clazz, String fieldName){
		boolean containsMethods = false;
		String getMethod = getGetMethodName(fieldName);
		String setMethod = getSetMethodName(fieldName);

		if(containsClassMethod(clazz, getMethod) && containsClassMethod(clazz, setMethod)){
			containsMethods = true;
		}

		return containsMethods;
	}

	/** Verify if a class contains a method name. If it contains this method name, it returns true, otherwise it returns false.
	 *
	 * @param clazz
	 * @param methodName
	 * @return
	 */
	public static boolean containsClassMethod(Class<?> clazz, String methodName) {
		boolean contains = false;
		Method[] arrayMethods = clazz.getMethods();
		for(Method method: arrayMethods){
			if(method.getName().equals(methodName)){
				contains = true;
			}
		}
		return contains;
	}

	/** Return if the object contains two methods, setMethodName and getMethodName.
	 *
	 * @param object
	 * @param setMethodName
	 * @param getMethodName
	 * @return It returns True it the object contains setMethodName and getMethodName. Otherwise it returns False.
	 */
	public static boolean containsGetAndSetMethodName(Object object, String setMethodName, String getMethodName){
		return containsMethodName(object, setMethodName) && containsMethodName(object, getMethodName);
	}

	/** Return the set method name for the field as parameter.
	 *
	 * @param field
	 * @return
	 */
	public static String getSetMethodName(String field){
		return SET_PREFIX_METHOD + field.substring(0, 1).toUpperCase() + field.substring(1, field.length());
	}

	/** Return the get method name for the field as parameter.
	 *
	 * @param field
	 * @return
	 */
	public static String getGetMethodName(String field){
		return GET_PREFIX_METHOD + field.substring(0, 1).toUpperCase() + field.substring(1, field.length());
	}

	/** Return the get method name for a boolean field with name as "field" parameter.
	 *
	 * @param field
	 * @return
	 */
	public static String getBooleanGetMethodName(String field){
		return GET_BOOLEAN_PREFIX_METHOD + field.substring(0, 1).toUpperCase() + field.substring(1, field.length());
	}


	/** Return a method of the object as parameter with name "methodName" and the class parameters "classParameters".
	 *
	 * @param object
	 * @param methodName
	 * @param classParameters
	 * @return A method of object with a method name and classParameters.
	 */
	public static Method getMethod(Object object, String methodName, Class<?>[] classParameters){
		Class<?> clazzObject = object.getClass();
		Method method = null;
		try {
			method = clazzObject.getMethod(methodName, classParameters);
		} catch (SecurityException e) {
			logger.error("There was an error in the securiry -> ", e);
		} catch (NoSuchMethodException e) {
			logger.error("Not found method '" + methodName + "' in the object class: " + clazzObject.getSimpleName() + ".", e);
		}
		return method;
	}

	/** Invoke a method with the methodName as parameter. First it gets the method object with the methodName, and
	 *  then it invokes the method and returns the object as result. The method's name  to invoke the method is
	 *  @see <code>invokeMethodWithoutParameters(Object object, Method methodToInvoke)</code>>
	 *
	 * @param object
	 * @param methodName
	 * @return Returns the object returned by the method invocation.
	 */
	public static Object invokeMethodWithoutParameters(Object object, String methodName){
		Method method = getMethodWithoutParameters(object, methodName);
		return invokeMethodWithoutParameters(object, method);
	}

	/** Invoke an static method without parameters in the class "clazzName". The static method name is "methodName".
	 *  It returns the object returned by the static method. Otherwise it returns null.
	 *
	 * @param clazzName
	 * @param methodName
	 * @return
	 */
	public static Object invokeStaticMethodWithoutParameters(String clazzName, String methodName){
		Class<?> clazz = ReflectionHelper.getClassFrom(clazzName);
		Object obj = invokeStaticMethodWithoutParameters(clazz, methodName);
		return obj;
	}

	public static Object invokeStaticMethodWithoutParameters(Class<?> clazz, String methodName){
		Method method = null;
		Object obj = null;
		try {
			method = clazz.getMethod(methodName, NULL_CLASS_ARRAY);
			obj = method.invoke(clazz, NULL_OBJECT_ARRAY);
		} catch (SecurityException e) {
			logger.error("There was an error in the securiry -> ", e);
		} catch (NoSuchMethodException e) {
			logger.error("Not found method " + methodName + " in the object class: " + clazz.getSimpleName() + ".", e);
		} catch (IllegalArgumentException e) {
			logger.error("Not found method without arguments: " + methodName + " in the object class: " + clazz.getSimpleName() + ".", e);
		} catch (IllegalAccessException e) {
			logger.error("There was an ilegal access error -> ", e);
		} catch (InvocationTargetException e) {
			logger.error("There was an invocation target error -> ", e);
		}
		return obj;
	}

	/** Invoke a method as parameter without parameters. This method is used by
	 *  <code>invokeMethodWithoutParameters(Object object, String methodName)</code>
	 *
	 * @param object
	 * @param methodToInvoke
	 * @return Returns the object returned by the method invocation.
	 */
	public static Object invokeMethodWithoutParameters(Object object, Method methodToInvoke){
		return invokeMethodWithParameters(object, methodToInvoke, NULL_OBJECT_ARRAY);
	}

	/** Invoke an object (as parameter) method with its method name, classParameters and objects parameters.
	 *  First it get the object method with <code>getMethod(Object object, String methodName, Class[] classParameters)</code>
	 *  Then it invoke the method with the object / parameters.
	 *
	 * @param object
	 * @param methodName
	 * @param classParameters
	 * @param objectsParameters
	 * @return The object as result to invoke the method.
	 */
	public static Object invokeMethodWithParameters(Object object, String methodName, Class<?>[] classParameters, Object[] objectsParameters){
		Method methodToInvoke = getMethod(object, methodName, classParameters);
		return invokeMethodWithParameters(object, methodToInvoke, objectsParameters);
	}

	/** Invoke an object method with its class and objects parameters.
	 *
	 * @param object
	 * @param methodToInvoke
	 * @param objectsParameters
	 * @return The object as result to invoke the method.
	 */
	public static Object invokeMethodWithParameters(Object object, Method methodToInvoke, Object[] objectsParameters){
		Object obj = null;
		try {
			obj = methodToInvoke.invoke(object, objectsParameters);
		} catch (IllegalArgumentException e) {
			logger.error("There are some illegals arguments in the method invocation: " + methodToInvoke.getName());
		} catch (IllegalAccessException e) {
			logger.error("There is an ileggal access in the method invocation: " + methodToInvoke.getName());
		} catch (InvocationTargetException e) {
			logger.error("There is an invocation target in the method: " + methodToInvoke.getName());
		}
		return obj;
	}

	/** Get all class type parameters from the list object like parameter.
	 *
	 * @param parametersList
	 * @return
	 */
	public static List<Class<?>> getParametersClassesTypes(List<Object> parametersList){
		List<Class<?>> parameterClasses = new ArrayList<Class<?>>();
		Object obj = null;

		for(int i = 0; i < parametersList.size(); i++){
			obj = parametersList.get(i);
			if(obj.getClass().equals(String.class)){
				parameterClasses.add(String.class);
			} else if(obj.getClass().equals(Integer.class)){
				parameterClasses.add(Integer.class);
			} else if(obj.getClass().equals(Boolean.class)){
				parameterClasses.add(Boolean.class);
			} else if(obj.getClass().equals(Character.class)){
				parameterClasses.add(Character.class);
			} else if(obj.getClass().equals(CharSequence.class)){
				parameterClasses.add(CharSequence.class);
			} else if(obj.getClass().equals(Class.class)){
				parameterClasses.add(Class.class);
			} else if(obj.getClass().equals(Short.class)){
				parameterClasses.add(Short.class);
			} else if(obj.getClass().equals(Serializable.class)){
				parameterClasses.add(Serializable.class);
			} else {
				parameterClasses.add(Object.class);
			}
		}
		return parameterClasses;
	}

	/** Get all other java primitives classes. They are:
	 *  - char.class
	 *  - boolean.class
	 *
	 * @return
	 */
	public static List<Class<?>> getOtherJavaPrimitiveClasses(){
		List<Class<?>> listClasses = new ArrayList<Class<?>>();
		listClasses.add(char.class);
		listClasses.add(boolean.class);
		return listClasses;
	}
	/** Gett all java primitives classes. They are:
	 * - char.classes
	 * - boolean.class
	 * - int.class
	 * - long.class
	 * - double.class
	 * - short.class
	 *
	 * @return
	 */
	public static List<Class<?>> getAllJavaPrimitiveClasses(){
		List<Class<?>> listAllClasses = getNumbersJavaPrimitiveClasses();
		listAllClasses.addAll(getOtherJavaPrimitiveClasses());
		return listAllClasses;
	}

	/** Get all numbers java primitives classes. They are:
	 * - int.class
	 * - long.class
	 * - dounle.class
	 * - short.class
	 *
	 * @return
	 */
	public static List<Class<?>> getNumbersJavaPrimitiveClasses(){
		List<Class<?>> listClasses = new ArrayList<Class<?>>();
		listClasses.add(int.class);
		listClasses.add(long.class);
		listClasses.add(double.class);
		listClasses.add(short.class);
		return listClasses;
	}

	/** Returns if clazz is a java primitive class. If clazz is a java primitive class, it returns true, otherwise
	 * it returns false.
	 *
	 * @param clazz
	 * @return
	 */
	public static boolean isAJavaPrimitiveClass(Class<?> clazz){
		return getAllJavaPrimitiveClasses().contains(clazz);
	}

	/** Return All basic java classic.
	 *
	 * @return
	 */
	public static List<Class<?>> getAllBasicJavaClasses(){
		List<Class<?>> basicClasses = new ArrayList<Class<?>>();
		basicClasses.add(String.class);
		basicClasses.add(Integer.class);
		basicClasses.add(Long.class);
		basicClasses.add(Short.class);
		basicClasses.add(Double.class);
		basicClasses.add(Boolean.class);
		basicClasses.add(Character.class);
		basicClasses.add(CharSequence.class);
		return basicClasses;
	}

	/** Return if a class is a basic java class. They are:
	 * - String.class
	 * - Integer.class
	 * - Long.class
	 * - Short.class
	 * - Double.class
	 * - Boolean.class
	 * - Character.class
	 * - CharSequence.class
	 *
	 * @param clazz
	 * @return
	 */
	public static boolean isABasicJavaClass(Class<?> clazz){
		return getAllBasicJavaClasses().contains(clazz);
	}

	/** Create a new instance from clazz.
	 *
	 * @param clazz
	 * @return a new object.
	 */
	public static Object createObject(Class<?> clazz){
		Object object = null;
		try {
			object = clazz.newInstance();
		} catch (InstantiationException e) {
			logger.error("An error occurred at instatiation object. May be " + clazz + " haven't a default constructor.");
		} catch (IllegalAccessException e) {
			logger.error("An illegal access occurred at object at class: '" + clazz + "'.");
		}
		return object;
	}

	/** Create a object's instance calling to the constructor with a parameter list.
	 *
	 * @param clazz
	 * @param listParameterObject
	 * @return a new object's instance.
	 */
	public static Object createObject(Class<?> clazz, List<Object> listParameterObject){
		Constructor<?>[] constructors = clazz.getConstructors();
		Class<?>[] parametersClass = null;
		Object newInstanceObject = null;

		for(Constructor<?> constructor: constructors){
			parametersClass = constructor.getParameterTypes();
			if(areEqualsTypeClass(parametersClass, listParameterObject)){
				try {
					newInstanceObject = constructor.newInstance(listParameterObject.toArray());
				} catch (IllegalArgumentException e) {
					logger.error("Some illegal argument to invoke method has occurred: '" + constructor.getName() + "'.");
				} catch (InstantiationException e) {
					logger.error("An error occurred at instatiation object. May be " + clazz + " haven't a default constructor: '" + constructor.getName() + "'.");
				} catch (IllegalAccessException e) {
					logger.error("An illegal access to constructor has occurred: '" + constructor.getName() + "'.");
				} catch (InvocationTargetException e) {
					logger.error("An invocation target error has occurred when invoke to constructor: '" + constructor.getName() + "'.");
				}
			}
		}
		return newInstanceObject;
	}

	/** Verify if classes array are equals to list object classes or if someone class's classes array is an interface, verify if the current index
	 * of list objects implements this interfaces. It returns true if classes array are equals to list object classes.
	 * If the length / size classes array and listObject are different, it returns false.
	 *
	 * @param classes
	 * @param listObjects
	 * @return true if the classes array are equals to list object classes.
	 */
	public static boolean areEqualsTypeClass(Class<?>[] classes, List<Object> listObjects){
		int size = 0;
		boolean areEqualsType = false;
		if(classes != null & listObjects != null){
			if(classes.length == listObjects.size()){
				size = classes.length;
			}
		}

		if(size > 0){
			areEqualsType = true;
		}

		for(int i = 0; i < size; i++){
			if(areEqualsType && (
								(classes[i].isInterface() && !implementsInterfaceRecursive(listObjects.get(i).getClass(), classes[i]) ||
								 (!classes[i].isInterface() && !classes[i].equals(listObjects.get(i).getClass())))
								)){
				areEqualsType = false;
			}
		}
		return areEqualsType;
	}

	/** Create a new instance from a class name.
	 *
	 * @param className
	 * @return an object from class name.
	 */
	public static Object createObject(String className){
		Class<?> clazz = getClassFrom(className);
		Object object = createObject(clazz);
		return object;
	}

	/** Find at the object all method where its name be equals to the method name as parameter.
	 * 	It returns a list with all methods with the same name, but with differents parameters.
	 *
	 * @param obj
	 * @param methodName
	 * @return a list's method with method name as parameter.
	 */
	public static List<Method> getMethods(Object obj, String methodName){
		return getMethods(obj.getClass(), methodName);
	}

	/** Find at the class all methods where its name be equals to the method name as parameter.
	 * It returns a list with all methods with the same name, but with differents parameteres.
	 *
	 * @param clazz
	 * @param methodName
	 * @return a list's method with method name as parameter.
	 */
	public static List<Method> getMethods(Class<?> clazz, String methodName){
		Method[] arrayMethod = clazz.getMethods();
		List<Method> resultMethodList = new ArrayList<Method>();
		for(Method currentMethod: arrayMethod){
			if(currentMethod.getName().equalsIgnoreCase(methodName)){
				resultMethodList.add(currentMethod);
			}
		}
		return resultMethodList;
	}

	/** Return method with the same parameters types.
	 *
	 * @param listMethod
	 * @param parameters
	 * @return method with equals parameters types.
	 */
	@SuppressWarnings("unchecked")
	public static Method findMethodAt(List<Method> listMethod, Object[] parameters){
		Method methodResult = null;
		List<Object> listObjects = (List<Object>) CollectionHelper.convertTo(parameters);
		if(listMethod.size() > 1){
			for(Method method : listMethod){
				if(methodResult == null && areEqualsTypeClass(method.getParameterTypes(), listObjects)){
					methodResult = method;
				}
			}
		} else if(listMethod.size() == 1){
			methodResult = listMethod.get(0);
		}
		return methodResult;
	}

	/** Get all fields declared in the class.
	 *
	 * @param clazz to get all its fields.
	 * @return fields' array.
	 * @see Class#getDeclaredFields()
	 */
	public static Field[] getFieldsDeclaredFor(Class<?> clazz){
		return clazz.getDeclaredFields();
	}

	/**
	 * Get all fields in the class.
	 *
	 * @param clazz to get all its fields.
	 * @return fields' array.
	 * @see Class#getFields()
	 */
	public static Field[] getFieldsFor(Class<?> clazz){
		return clazz.getFields();
	}


	/** Get an field value for an instance object.
	 *
	 * @param object to get field value.
	 * @param field to get value.
	 * @return field value from object.
	 */
	public static Object getObjectForField(Object object, Field field){
		Object objectFromField = null;
		try {
			field.setAccessible(true);
			objectFromField = field.get(object);
		} catch (IllegalArgumentException e) {
			logger.error("Illegal argument to get field [" + field.getName() + "] value.", e);
		} catch (IllegalAccessException e) {
			logger.error("Illegal access to get field [" + field.getName() + "] value.", e);
		}
		return objectFromField;
	}

	/** Find all method for class.
	 *
	 * @param clazz to find its methods.
	 * @return a methods' array.
	 */
	public static Method[] getAllMethodFor(Class<?> clazz){
		if(clazz != null){
			return clazz.getMethods();
		}
		return new Method[]{};
	}

	/** Find all method with a specific modifier at class.
	 *
	 * @param modifier to filter method.
	 * @param clazz to find its methods.
	 * @return methods' array.
	 */
	public static Method[] getAllMethodWith(Modifier modifier, Class<?> clazz){
		Method[] methods = getAllMethodFor(clazz);
		List<Method> listMethods = new ArrayList<Method>();
		for(Method m: methods){
			if(modifier.equals(m.getModifiers())){
				listMethods.add(m);
			}
		}
		return (Method[]) listMethods.toArray();
	}

	public static Method[] getAllMethodWith(Class<? extends Annotation> annotation, Class<?> clazz){
		Method[] methods = getAllMethodFor(clazz);
		List<Method> listMethods = new ArrayList<Method>();
		for(Method m: methods){
			if(AnnotationHelper.hasAnnotation(m, annotation)){
				listMethods.add(m);
			}
		}
		Method[] a = new Method[listMethods.size()];
		int i = 0;
		for(Method m : listMethods){
			a[i] = m;
			i++;
		}
		return a;
	}

	public static Field[] getAllFieldWith(Class<? extends Annotation> annotation, Class<?> clazz){
		Field[] fields = getFieldsDeclaredFor(clazz);
		List<Field> listFields = new ArrayList<Field>();
		for(Field f: fields){
			if(AnnotationHelper.hasAnnotation(f, annotation)){
				listFields.add(f);
			}
		}
		Field[] a = new Field[listFields.size()];
		int i = 0;
		for(Field m : listFields){
			a[i] = m;
			i++;
		}
		return a;
	}

    /**
     * Determina si un tipo es instanciable o no (en otras palabras, si es una clase
     * concreta)
     *
     * @param aClass el tipo
     * @return true si es instanciable
     */
    public static <T> boolean isInstantiable(Class<T> aClass) {
        int modifiers = aClass.getModifiers();
        return !Modifier.isAbstract(modifiers) && !Modifier.isInterface(modifiers);
    }

    public static Field getFieldByName(Class<?> clazz, String name) {
        try {
            return clazz.getDeclaredField(name);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException("No existe el campo '" + name +
                    "' en un objeto de clase " + clazz.getName(), e);
        }
    }
    
    public static Field getFieldOrNullByName(Class<?> clazz, String name) {
        try {
            return clazz.getDeclaredField(name);
        } catch (NoSuchFieldException e) { }
        return null;
    }

    public static void setFieldValue(Object fieldOwner, String name, Object value) {
        setFieldValue(fieldOwner, getFieldByName(fieldOwner.getClass(), name), value);
    }

    public static void setFieldValue(Object fieldOwner, Field field, Object value) {
        try {
            boolean accessible = field.isAccessible();
            field.setAccessible(true);
            field.set(fieldOwner, value);
            field.setAccessible(accessible);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static Object getFieldValue(Object fieldOwner, String name) {
        return getFieldValue(fieldOwner, getFieldByName(fieldOwner.getClass(), name));
    }

    public static Object getFieldValue(Object fieldOwner, Field field) {
        try {
            boolean accessible = field.isAccessible();
            field.setAccessible(true);
            Object result = field.get(fieldOwner);
            field.setAccessible(accessible);
            return result;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static boolean isAnnotationPresent(Collection<Annotation> annotationList, final Class<? extends Annotation> annotationClass) {
        return getAnnotationOfType(annotationList,  annotationClass) != null;
    }

    @SuppressWarnings("unchecked")
    public static <T extends Annotation> T getAnnotationOfType(Collection<Annotation> annotationList, final Class<? extends Annotation> annotationClass) {
        return (T) CollectionUtils.find(annotationList, new Predicate<Annotation>() {
            public boolean evaluate(Annotation annotation) {
                return annotationClass.isAssignableFrom(annotation.getClass());
            }
        });
    }

	public static boolean matchParametersTypes(Method rowProcessorMethod, Class<?>[] typesParameters) {
		Class<?>[] methodParametersTypes = rowProcessorMethod.getParameterTypes();
		int methodParametersSize = methodParametersTypes != null ? methodParametersTypes.length :0;
		int parametersSize = typesParameters != null ? typesParameters.length :0;
		boolean match = true;
		if(methodParametersSize != parametersSize){
			match = false;
		}
		if(match){
			int i =0;
			for(Class<?> c: methodParametersTypes){
				if(match){
					match =	c.equals(typesParameters[i]) ||
							inheritClassFrom(typesParameters[i], c) ||
							implementsInterfaceRecursive(typesParameters[i], c);
				}
				i++;
			}
		}
		return match;
	}
}
